package org.lizf.service.impl;

import org.lizf.dao.SeckillDAO;
import org.lizf.dao.SuccessKilledDAO;
import org.lizf.dto.Exposer;
import org.lizf.dto.SeckillExecution;
import org.lizf.entity.Seckill;
import org.lizf.entity.SuccessKilled;
import org.lizf.enums.SeckillEnum;
import org.lizf.exception.RepeatKillException;
import org.lizf.exception.SeckillClosedException;
import org.lizf.exception.SeckillException;
import org.lizf.service.SeckillService;
import org.lizf.utils.MD5Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
public class SeckillServiceImpl implements SeckillService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SeckillDAO seckillDAO;

    @Autowired
    private SuccessKilledDAO successKilledDAO;

    public List<Seckill> getSecKillList() {
        return seckillDAO.queryAll(0,4);
    }

    public Seckill getSecKillById(long seckillId) {
        return seckillDAO.queryById(seckillId);
    }

    public Exposer exportSeckillURL(long seckillId,long userPhone) {
        Seckill seckill = this.getSecKillById(seckillId);
        if(null == seckill) {
            return new Exposer(false, seckillId);
        }
        Date startTime = seckill.getStartTime();
        Date endTime = seckill.getEndTime();
        Date now = new Date();
        if(now.compareTo(startTime) == -1 || now.compareTo(endTime) == 1) {
            return new Exposer(false,  seckillId, now.getTime(), startTime.getTime(), endTime.getTime());
        }
        String md5 = MD5Util.getMd5(seckillId);
        return new Exposer(true, md5, seckillId);
    }

    /**
     * 使用注解控制事务的优点
     * 1、开发团队达成一致约定，明确标注事务方法的编程风格
     * 2、保证事务方法的执行时间尽可能短
     * 3、不要穿插其他IO操作
     * 4、不是所有的方法都需要添加事务管理
     * @param seckillId
     * @param userPhone
     * @param md5
     * @return
     * @throws SeckillException
     * @throws RepeatKillException
     * @throws SeckillClosedException
     */
    @Transactional
    public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5) throws SeckillException, RepeatKillException, SeckillClosedException {
        if(md5 == null || !md5.equals(MD5Util.getMd5(seckillId))) {
            throw new SeckillException("数据被更改");
        }
        Date now = new Date();
        int updateCount = seckillDAO.reduceNumber(seckillId, now);
        if(updateCount <= 0) {
            throw new SeckillClosedException("秒杀关闭");
        } else {
            int insertCount = successKilledDAO.insertSuccessKilled(seckillId, userPhone);
            if(insertCount <= 0) {
                throw new RepeatKillException("重复购买");
            } else {
                SuccessKilled successKilled = successKilledDAO.queryByIdAndPhoneWithSeckill(seckillId, userPhone);
                return new SeckillExecution(seckillId, SeckillEnum.SUCCESS, successKilled);
            }
        }
    }
}
